#pragma once

#include <AVUIFrameworkTemplate.h>
#include <AVUITriggerCollection.h>
#include <AVUIItemStructList.h>
#include <AVUIIXamlResolutionContext.h>

namespace AVUI {

class Control;
class String;

/// <summary>Specifies the visual structure and behavioral aspects of a <see cref="T:System.Windows.Controls.Control" /> that can be shared across multiple instances of the control.</summary>
class ControlTemplate : public FrameworkTemplate, public IXamlResolutionContext
{
public:
    DECLARE_ELEMENT(ControlTemplate, FrameworkTemplate);

#pragma region Public Methods

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.Controls.ControlTemplate" /> class.</summary>
    ControlTemplate() : m_pTargetType(NULL) { }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.Controls.ControlTemplate" /> class with the specified target type.</summary>
    /// <param name="targetType">The type this template is intended for.</param>
    ControlTemplate(const Type* pTargetType) { ValidateTargetType(pTargetType, "targetType"); m_pTargetType = pTargetType; }

#pragma region Public Methods

#pragma region Public Properties

    /// <summary>Gets or sets the type for which this <see cref="T:System.Windows.Controls.ControlTemplate" /> is intended.</summary>
    /// <returns>The default value is null.</returns>
    /// <exception cref="T:System.ArgumentNullException">The <see cref="P:System.Windows.Controls.ControlTemplate.TargetType" /> property must not be null if the definition of the template has a <see cref="T:System.Windows.Controls.ContentPresenter" />.</exception>
    /// <exception cref="T:System.ArgumentException">The specified types are not valid. The <see cref="P:System.Windows.Controls.ControlTemplate.TargetType" /> of a <see cref="T:System.Windows.Controls.ControlTemplate" /> must be or inherit from a <see cref="T:System.Windows.Controls.Control" />, a <see cref="T:System.Windows.Controls.Page" />, or a <see cref="T:System.Windows.Navigation.PageFunctionBase" />.</exception>
    const Type* get_TargetType() { return m_pTargetType; }
    void set_TargetType(const Type* pValue) { ValidateTargetType(pValue, "value"); CheckSealed(); m_pTargetType = pValue; }
    IMPLEMENT_REFERENCE_PROPERTY(TargetType, Type, false);

    /// <summary>Gets a collection of <see cref="T:System.Windows.TriggerBase" /> objects that apply property changes or perform actions based on specified conditions.</summary>
    /// <returns>A collection of <see cref="T:System.Windows.TriggerBase" /> objects. The default value is null.</returns>
    TriggerCollection* get_Triggers();
    IMPLEMENT_READONLY_REFERENCE_PROPERTY(Triggers, TriggerCollection, false);

#pragma endregion Public Properties

protected:

#pragma region Protected Methods

    /// <summary>Checks the templated parent against a set of rules.</summary>
    /// <returns />
    /// <param name="templatedParent">The element this template is applied to.</param>
    /// <exception cref="T:System.ArgumentNullException">The <paramref name="templatedParent" /> must not be null.</exception>
    /// <exception cref="T:System.ArgumentException">The <see cref="P:System.Windows.Controls.ControlTemplate.TargetType" /> of a <see cref="T:System.Windows.Controls.ControlTemplate" /> must match the type of the <see cref="T:System.Windows.Controls.Control" /> that it is being applied to.</exception>
    /// <exception cref="T:System.ArgumentException">You must associate the <see cref="T:System.Windows.Controls.ControlTemplate" /> with a <see cref="T:System.Windows.Controls.Control" /> by setting the <see cref="P:System.Windows.Controls.Control.Template" /> property before using the <see cref="T:System.Windows.Controls.ControlTemplate" /> on the <see cref="T:System.Windows.Controls.Control" />.</exception>
    virtual void ValidateTemplatedParent(FrameworkElement* pTemplatedParent) AVUI_OVERRIDE;

#pragma endregion Protected Methods

public:

#pragma region Internal Methods

    virtual void SetTargetTypeInternal(const Type* pTargetType) AVUI_OVERRIDE { set_TargetType(pTargetType); }

#pragma endregion Internal Methods

#pragma region Internal Properties

    static const Type* get_DefaultTargetType() { return &GET_TYPE(Control); }
    virtual const Type* get_TargetTypeInternal() AVUI_OVERRIDE { if(get_TargetType() != NULL) return get_TargetType(); return get_DefaultTargetType(); }
    virtual TriggerCollection* get_TriggersInternal() AVUI_OVERRIDE { return get_Triggers(); }

#pragma endregion Internal Properties

#pragma region WPFG / Deviation

    const Type* GetPropertyResolutionContext(Object* pObjectCurrent);
    Property* GetValueConverterContext(Object* pObjectCurrent);

#pragma endregion WPFG / Deviation

private:

#pragma region Private Methods

    void ValidateTargetType(const Type* pTargetType, const char* szArgName);

#pragma endregion Private Methods

#pragma region Private Fields

    const Type* m_pTargetType;
    TRefCountedPtr<TriggerCollection> m_pTriggers;

#pragma endregion Private Fields

};



}; // namespace AVUI
